# Author: Benjamin Eriksson
# Date: 18/08-2013 (DD/MM-YYYY)
# Please read the analysis at 
# https://docs.google.com/document/d/17AX-zRyqKApqhBJCtPUycnwvy_u2rJpxKZjXs9osLIE/edit?usp=sharing
# Feel free to comment in the doc.


# Im not a python programmer so Im not sure how 
# standard __future__ is but I need real division, hope it is acceptable. 
from __future__ import division
import random
import sys
import math


class Player: 
    
    
    def __init__(self):    
        self.sf = 0                     # Food at start
        self.tot = 0                    # Total number of moves
        self.P_start = 0                # Players at the start
        self.list = []                  # List with all reputations
        
            
    def hunt_choices(
                    self,
                    round_number,
                    current_food,
                    current_reputation,
                    m,
                    player_reputations,
                    ):

        
        
        ''' Initialization '''
        if round_number == 1:
            self.sf  = current_food
            self.tot = 0    
            self.P_start = len(player_reputations) 
            self.firstLateGameRound = 1
        
        

        ''' Variables '''
        # Our list of moves
        hunt_decisions = []
        
        # Number of players 
        P = len(player_reputations)
        
        # The total amount of moves (hunt / slacks)
        # Used in late game for profiling
        self.tot += P-1

        # The expected value of m 
        m_e = 0.0
        for R in player_reputations:
            m_e += R 
        m_e *= P-1
        size_m_e = (m_e/m)
        
        # Calculate standard deviation
        mean = 0
        u = 0
        std = 0
        
        for R in player_reputations:
            mean += R
        mean += current_reputation
        mean = mean/(P)
        
        for R in player_reputations:
            u += (R-mean)*(R-mean)
            
        std = math.sqrt(u/(P-1))

 
        if(P/self.P_start>0.7 and P > 10):
            # The case where the bonus is assured to be or not be claimed. 
            if( (size_m_e < 1/3 or size_m_e > 3) and current_reputation > mean-std):
                for R in player_reputations:
                    if R < (mean+std):
                        hunt_decisions.append('s')
                    else:
                        hunt_decisions.append('h')
            # The normal case 
            else:    
                for R in player_reputations:
                    if R < (mean-std):
                        hunt_decisions.append('s')
                    else:
                        hunt_decisions.append('h')
                    
        elif(P/self.P_start<=0.7 and P/self.P_start > 0.01 and P > 10):
            # The case where the bonus is assured to be or not be claimed. 
            if( (size_m_e < 1/2 or size_m_e > 2) and current_reputation > mean):
                for R in player_reputations:
                    if R < (mean+std):
                        hunt_decisions.append('s')
                    else:
                        hunt_decisions.append('h')
            # The normal case 
            else:    
                for R in player_reputations:
                    if R < (mean - 0.5*std):
                        hunt_decisions.append('s')
                    else:
                        hunt_decisions.append('h')
                    
        else:
            # Updates the list every 10 turn
            # This is used to avoid errors in the approximation. Player with similar reputation might merge over time. 
            if round_number % 10 == 0:
                # A list with all the reputations of the players    
                self.list = []
                for x in player_reputations:
                    self.list.append(x)

            else:
                # The new list for the next round
                newList = range(len(self.list))

                # Algorithm explained in the paper
                for x in  range(len(player_reputations)):
                    for y in range(len(self.list)):
                        h = self.tot * self.list[y]
                        
                        if ( player_reputations[x] >= h/(self.tot+P) ) and (player_reputations[x] <= (h+P)/(self.tot+P) ):
                            newList[y] = player_reputations[x]

 
            # The decision tree
            for R in range(len(player_reputations)):
                # Every odd round
                # I picked odd because the list is refreshed on a even round (% 10) and 
                # at that time newList is undefined
                if(len(self.list) > 0  and round_number % 2 != 0):
                    # If the trend is negative
                    if(newList[R] - self.list[R] < 0):
                        # Then the reputation has to be higher                
                        if player_reputations[R] < (mean+std):
                            hunt_decisions.append('s')
                        else:
                            hunt_decisions.append('h')
                            
                    # If the trend is positive
                    else:                
                        # The reputation can be lower
                        if player_reputations[R] < (mean-std):
                            hunt_decisions.append('s')
                        else:
                            hunt_decisions.append('h')
                            
                # Every even round
                else:
                    # If the bonus is assured to be claimed or not claimed
                    if( (size_m_e < 2/3 or size_m_e > 3/2) and current_reputation > mean):
                        # The likelihood of slacking is higer
                        if R < (mean+std):
                            hunt_decisions.append('s')
                        else:
                            hunt_decisions.append('h')
                    
                    else:   
                        # If the bonus is not assured the program will hunt
                        # with everyone with a reputation above the mean
                        # If our own reputation is below the mean it will hunt.
                        if (R < (mean) and current_reputation > mean):
                            hunt_decisions.append('s')
                        else:
                            hunt_decisions.append('h')
                                

        return hunt_decisions

    def hunt_outcomes(self, food_earnings):
        '''Required function defined in the rules'''
        pass
        

    def round_end(self, award, m, number_hunters):
        '''Required function defined in the rules'''
        pass
        
